package com.deepgames.mud.gobject;

import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;

import com.deepgames.mud.core.InternalCode;
import com.deepgames.mud.gobject.data.Player;
import com.deepgames.mud.gobject.data.Zone;

/**
 * Acts as a front end to an object database, generating DAO-like objects for
 * 	reading and writing game objects.
 * 
 * @author Zack Hoffmann
 * @version 0.1
 *
 */
public class GobjectExtractor {
	
	private Logger log;
	private Connection dbCon;
	private List<Zone> zones;
	private Map<String,Player> playersByID;
	private Map<String,Player> playersByName;
	
	/**
	 * Basic constructor.  System properties must be set beforehand.
	 */
	public GobjectExtractor() {
		log = Logger.getLogger(GobjectExtractor.class.getName());
		log.setLevel(Level.parse(System.getProperty("deepmud.log.level")));
		this.dbConnect();
		this.zones = new ArrayList<Zone>();
		this.playersByID = new HashMap<String,Player>();
		this.playersByName = new HashMap<String,Player>();
	}
	
	/**
	 * Gain direct access to underlying database connection.
	 * 
	 * @return				The current database connection.
	 */
	public Connection getDbCon() {
		return dbCon;
	}

	public List<Zone> getZones() {
		return zones;
	}
	
	public Collection<Player> getPlayers() {
		return playersByID.values();
	}
	
	public Player getPlayerByID(String playerID) {
		return playersByID.get(playerID);
	}
	
	public Player getPlayerByName(String playerName) {
		return playersByName.get(playerName);
	}
	
	/**
	 * Add a new player to the world.  This addition is not automatically
	 * 	reflected in the database.  A separate database transaction must take
	 * 	place to persist the player Gobject.
	 * 
	 * @param newPlayer		The new player Gobject to add to the world.
	 * @return				Status code.  {@link InternalCode}
	 */
	public int addPlayer(Player newPlayer) {
		int status = InternalCode.SUCCESS;
		
		playersByID.put(newPlayer.getGobjectID(), newPlayer);
		playersByName.put(newPlayer.getShortName(), newPlayer);
		
		return status;
	}

	/**
	 * Internal helper to setup the database connection.  JDBC configuration
	 * 	properties are expected to be set.
	 */
	private void dbConnect() {
		String url = System.getProperty("deepmud.jdbc.url");
		String username = System.getProperty("deepmud.jdbc.user");
		String password = System.getProperty("deepmud.jdbc.pass");
		boolean create = System.getProperty("deepmud.jdbc.createnew").equals("true");
		String classpath = System.getProperty("class.path");
		
		System.setProperty("derby.system.home", classpath + "/mudDB");
		
		if (create)
			url += ";create=true";		
		
		try {
			Class.forName("org.apache.derby.jdbc.EmbeddedDriver");
			dbCon = DriverManager.getConnection(url, username, password);
			if(create) {
				System.setProperty("deepmud.jdbc.createnew", "false");
				System.getProperties().storeToXML(new FileOutputStream("properties.xml"), "New database created.");
			}
		} catch (SQLException e) {
			log.severe("Database connection could not be established.  Please reconfigure.");
			log.severe(e.toString());
			e.printStackTrace();
		} catch (FileNotFoundException e) {
			log.severe("Could not resolve change to properties file.");
			log.severe(e.toString());
			e.printStackTrace();
		} catch (IOException e) {
			log.severe("Could not resolve change to properties file.");
			log.severe(e.toString());
			e.printStackTrace();
		} catch (ClassNotFoundException e) {
			log.severe("Could not find embedded JDBC driver.");
			log.severe(e.toString());
			e.printStackTrace();
		}
	}
}
